/*
 * 础石OS	-- 设备树
 *
 * Copyright (C) 2022 国科础石(重庆)软件有限公司
 *
 * 作者: Hengxing Wu<wuhengxing@kernelsoft.com>
 *
 * License terms: GNU General Public License (GPL) version 3
 *
 */

#ifndef __DIM_SUM_DT_H
#define __DIM_SUM_DT_H

#include <linux/compiler.h>
#include <dim-sum/double_list.h>
#include <dim-sum/smp_rwlock.h>
#include <dim-sum/types.h>
#include <dim-sum/ref.h>
#include <dim-sum/errno.h>
#include <dim-sum/device.h>
typedef u32 phandle;
typedef u32 ihandle;
#ifndef TRUE
#define TRUE	1
#endif

#ifndef FALSE
#define FALSE	0
#endif

#define DT_SHORT_NAME_SIZE			32
#define DT_TYPE_SIZE				32
#define DT_COMPAT_SIZE				128

#define DT_PATH_SEPARATOR			'/'
#define DT_PATH_SEPARATOR_STRING		"/"

/*
 *设备树节点的设备类型
 */
#define DT_DEVICE_TYPE_VAL_CPU			"cpu"
#define DT_DEVICE_TYPE_VAL_GUEST		"guest"
#define DT_DEVICE_TYPE_VAL_VCPU			"vcpu"
#define DT_DEVICE_TYPE_VAL_RAM			"ram"
#define DT_DEVICE_TYPE_VAL_ALLOCED_RAM		"alloced_ram"
#define DT_DEVICE_TYPE_VAL_COLORED_RAM		"colored_ram"
#define DT_DEVICE_TYPE_VAL_SHARED_RAM		"shared_ram"
#define DT_DEVICE_TYPE_VAL_ROM			"rom"
#define DT_DEVICE_TYPE_VAL_ALLOCED_ROM		"alloced_rom"
#define DT_DEVICE_TYPE_VAL_COLORED_ROM		"colored_rom"
#define DT_DEVICE_TYPE_VAL_SHARED_ROM		"shared_rom"

#define DT_CONSOLE_PROP_NAME			"console"
#define DT_STDOUT_PROP_NAME			"stdout-path"
#define DT_BOOTARGS_PROP_NAME			"bootargs"
#define DT_BOOTCMD_PROP_NAME			"bootcmd"

#define DT_VMMINFO_NODE_NAME			"vmm"
#define DT_GUESTINFO_NODE_NAME			"guests"
#define DT_VCPUS_NODE_NAME			"vcpus"
#define DT_VCPU_TEMPLATE_NODE_NAME		"vcpu_template"
#define DT_ENDIANNESS_PROP_NAME			"endianness"
#define DT_ENDIANNESS_VAL_BIG			"big-endian"
#define DT_ENDIANNESS_VAL_LITTLE		"little-endian"
#define DT_START_PC_PROP_NAME			"start_pc"
#define DT_PRIORITY_PROP_NAME			"priority"
#define DT_TIME_SLICE_PROP_NAME			"time_slice"
#define DT_ADDRSPACE_NODE_NAME			"aspace"
#define DT_GUESTIRQCNT_PROP_NAME		"guest_irq_count"

/*
 *描述guest地址块空间的类型
 */
#define DT_MANIFEST_TYPE_PROP_NAME		"manifest_type"
#define DT_MANIFEST_TYPE_VAL_REAL		"real"
#define DT_MANIFEST_TYPE_VAL_VIRTUAL		"virtual"
#define DT_MANIFEST_TYPE_VAL_ALIAS		"alias"

/*
 *描述guest设备地址块的类型
 */
#define DT_ADDRESS_TYPE_PROP_NAME		"address_type"
#define DT_ADDRESS_TYPE_VAL_MEMORY		"memory"
#define DT_ADDRESS_TYPE_VAL_IO			"io"

/*
 *guest资源配置文件中用来描述地址属性的关键字
 */
#define DT_MEMORY_PHYS_ADDR_PROP_NAME		"physical_addr"
#define DT_MEMORY_PHYS_SIZE_PROP_NAME		"physical_size"
#define DT_GUEST_PHYS_PROP_NAME			"guest_physical_addr"
#define DT_HOST_PHYS_PROP_NAME			"host_physical_addr"
#define DT_ALIAS_PHYS_PROP_NAME			"alias_physical_addr"
#define DT_PHYS_SIZE_PROP_NAME			"physical_size"

#define DT_ALIGN_ORDER_PROP_NAME		"align_order"
#define DT_FIRST_COLOR_PROP_NAME		"first_color"
#define DT_NUM_COLORS_PROP_NAME			"num_colors"
#define DT_SHARED_MEM_PROP_NAME			"shared_mem"
#define DT_MAP_ORDER_PROP_NAME			"map_order"

#define DT_VCPU_AFFINITY_PROP_NAME		"affinity"
#define DT_VCPU_POWEROFF_PROP_NAME		"poweroff"
#define DT_TASKS_AFFINITY_PROP_NAME		"tasks_affinity"

#if defined(CONFIG_SPARC)
#define DT_ROOT_NODE_ADDR_CELLS_DEFAULT 2
#else
#define DT_ROOT_NODE_ADDR_CELLS_DEFAULT 1
#endif

#define DT_ROOT_NODE_SIZE_CELLS_DEFAULT 1

/*
 *设备树节点属性结构体
 */
struct property {
	/*
	 *链表节点
	 */
	struct double_list list;

	/*
	 *设备树节点属性名
	 */
	char name[DT_SHORT_NAME_SIZE];

	/*
	 *设备树节点属性值
	 */
	void *value;

	/*
	 *设备树节点属性值长度
	 */
	u32 len;
};

/*
 *设备树与驱动匹配对应的数据结构
 */
struct dt_device_id {
	char name[DT_SHORT_NAME_SIZE];
	char type[DT_TYPE_SIZE];
	char compatible[DT_COMPAT_SIZE];
	const void *data;
};


struct dt_nidtbl {
	u32 signature;
	char subsys[DT_SHORT_NAME_SIZE];
	const struct dt_device_id nodeid;
};

/**
 * 代码形式定义设备树节点
 */
#define DT_NIDTBL_DECLARE(nid, _subsys, _name, _type, _compat, _data) \
__nidtbl struct dt_nidtbl __##nid = { \
	.signature = NIDTBL_MAGIC, \
	.subsys = (_subsys), \
	.nodeid.name = (_name), \
	.nodeid.type = (_type), \
	.nodeid.compatible = (_compat), \
	.nodeid.data = (_data), \
}

/**
 * 设备树节点
 */
struct device_node {
	/*====私有成员数据=====*/
	/*
	 *链表节点，用于挂入其他node
	 */
	struct double_list list;
	struct ref_count ref_count;

	/*
	 *链表节点，描述当前node的属性值
	 */
	struct {
		struct smp_rwlock  lock;
		struct double_list list;
	} prop;

	/*
	 *链表节点，描述当前node的子node
	 */
	struct {
		struct smp_rwlock  lock;
		struct double_list list;
	} child;


	/*====公开成员数据=====*/
	char name[DT_SHORT_NAME_SIZE];
	struct device_node *parent;
	/*
	 *架构相关的代码可以利用此指针传递数据到设备驱动
	 */
	void *system_data;
	void *priv;
};

#define MAX_PHANDLE_ARGS 16
struct dt_phandle_args {
	struct device_node *node;
	int args_count;
	uint32_t args[MAX_PHANDLE_ARGS];
};

/*
 *设备树节点匹配时的回调函数指针
 */
typedef void (*node_found_cb)(struct device_node *node,
			      const struct dt_device_id *match,
			      void *data);

/*
 *从cell地址处，读取size数量的u32数据，转换成u64
 */
static inline u64 dt_read_number(const u32 *cell, int size)
{
	u64 r = 0;

	for (; size--; cell++)
		r = (r << 32) | be32_to_cpu(*cell);

	return r;
}

#ifdef CONFIG_USE_FDT

int dt_addr_cells(const struct device_node *node);
int dt_size_cells(const struct device_node *node);

#define for_each_property_of_node(pp, node) \
		list_for_each_entry(pp, &node->prop.list, list)

const void *dt_get_property(const struct device_node *node, const char *name);
u32 dt_property_size(const struct device_node *node, const char *name);
const void *dt_get_property_and_size(const struct device_node *node, const char *name, u32 *out);
bool dt_have_property(const struct device_node *node);
int dt_set_property(struct device_node *node, const char *name, void *value, u32 len);
struct property *dt_find_property(const struct device_node *node, const char *name);
int dt_delete_property(struct device_node *node, const char *name);
static inline bool dt_read_bool(const struct device_node *node, const char *propname)
{
	struct property *prop = dt_find_property(node, propname);

	return prop ? TRUE : FALSE;
}

int dt_read_u32_index(const struct device_node *node, const char *name, u32 *out, int index);
int dt_read_u32_array(const struct device_node *node, const char *name, u32 *out, size_t sz);
static inline int dt_read_u32(const struct device_node *node, const char *name, u32 *out)
{
	return dt_read_u32_array(node, name, out, 1);
}

int dt_read_u64_index(const struct device_node *node, const char *name, u64 *out, int index);
int dt_read_u64_array(const struct device_node *node, const char *name, u64 *out, size_t sz);
static inline int dt_read_u64(const struct device_node *node, const char *name, u64 *out)
{
	return dt_read_u64_array(node, name, out, 1);
}

int dt_read_string(const struct device_node *node, const char *name, const char **out);
int dt_match_string(struct device_node *node, const char *name, const char *string);
int dt_count_strings(struct device_node *node, const char *name);
int dt_read_string_index(struct device_node *node, const char *name, int index, const char **out);
const u32 *dt_next_u32(struct property *pp, const u32 *cur, u32 *val);
const char *dt_next_string(struct property *pp, const char *cur);

/**
 *增加/减少设备树节点引用值
 */
struct device_node *dt_node_hold(struct device_node *node);
void dt_node_loosen(struct device_node *node);
struct device_node *dt_node_add(struct device_node *parent, const char *name);
int dt_node_remove(struct device_node *node);
int dt_node_dup(struct device_node *parent, const char *name, struct device_node *src);
int dt_node_get_path(char *out, size_t out_len, const struct device_node *node);
struct device_node *dt_get_parent(const struct device_node *node);
struct device_node *dt_get_child_by_path(struct device_node *node, const char *path);
struct device_node *dt_find_node_by_path(const char *path);
const struct dt_device_id *dt_match_node(const struct dt_device_id *matches,
					 const struct device_node *node);
struct device_node *dt_find_matching_node(struct device_node *node,
					  const struct dt_device_id *matches);
void dt_iterate_matching_node(struct device_node *node,
			      const struct dt_device_id *matches,
			      node_found_cb found,
			      void *found_data);
int is_device_compatible(const struct device_node *node, const char *compatible);
bool is_device_available(const struct device_node *node);
bool is_device_big_endian(struct device_node *node);

#define for_each_child_of_node(child, node) \
	for (child = dt_get_next_child(node, NULL); \
	     child; \
	     child = dt_get_next_child(node, child))
bool is_node_have_child(const struct device_node *node);
struct device_node *dt_get_next_child(const struct device_node *node, struct device_node *cur);
struct device_node *dt_find_by_phandle(u32 phandle);
struct device_node *dt_parse_phandle(const struct device_node *node,
				     const char *phandle_name,
				     int index);
int dt_parse_phandle_with_args(const struct device_node *node,
			       const char *list_name,
			       const char *cells_name,
			       int index,
			       struct dt_phandle_args *out);
int dt_phandle_count_with_args(const struct device_node *node,
			       const char *list_name,
			       const char *cells_name);
int dt_get_clock_freq(struct device_node *node, u32 *clock_freq);

struct device_node *dt_irq_find_parent(struct device_node *child);
int dt_irq_parse_raw(const __be32 *addr, 
				   struct dt_phandle_args *out_irq);
int dt_irq_parse_one(struct device_node *device, u32 index, 
				   struct dt_phandle_args *out_irq);

/**
 * 获取设备的中断个数
 */
u32 dt_irq_count(struct device_node *device);

/**
 * 解析并映射中断
 * dev: 要被映射中断的设备树节点
 * index: 映射的中断index
 */
unsigned int dt_recognize_irq(struct device_node *dev, int index);

phys_addr_t dt_get_addr(struct device_node *node, u64 *size, int index);
void __iomem *dt_reg_map(struct device_node *node, int index);
int dt_reg_name_to_index(struct device_node *node, const char *regname);
void __iomem *dt_reg_map_byname(struct device_node *node, const char *regname);
void __iomem *dt_reg_request_and_map(struct device_node *node, int index, const char *name);
int dt_reg_unmap_and_free(struct device_node *node, void *va, int index);

int dt_reserved_memory_init(void);

u32 dt_nidtbl_count(void);
struct dt_nidtbl *dt_nidtbl_get(int index);
const struct dt_device_id *dt_nidtbl_create_matches(const char *subsys);
void dt_nidtbl_destroy_matches(const struct dt_device_id *matches);
int dt_init(void);

static inline const char *dt_node_full_name(const struct device_node *np)
{
	return np ? np->name : "<no-node>";
}

void *dt_get_match_data(const struct device *dev);

#else
static inline int dt_addr_cells(const struct device_node *node)
{
	return 0;
}

static inline int dt_size_cells(const struct device_node *node)
{
	return 0;
}

#define for_each_property_of_node(pp, node) \
		list_for_each_entry(pp, &node->prop.list, list)

static inline const void *dt_get_property(const struct device_node *node, const char *name)
{
	return NULL;
}

static inline u32 dt_property_size(const struct device_node *node, const char *name)
{
	return 0;
}

static inline bool dt_have_property(const struct device_node *node)
{
	return false;
}

static inline int dt_set_property(struct device_node *node, const char *name, void *value, u32 len)
{
	return -ENOSYS;
}

static inline struct property *dt_find_property(const struct device_node *node, const char *name)
{
	return NULL;
}

static inline int dt_delete_property(struct device_node *node, const char *name)
{
	return -ENOSYS;
}

static inline bool dt_read_bool(const struct device_node *node, const char *propname)
{
	return FALSE;
}

static inline int dt_read_u32_index(const struct device_node *node, const char *name, u32 *out, int index)
{
	return -ENOSYS;
}

static inline int dt_read_u32_array(const struct device_node *node, const char *name, u32 *out, size_t sz)
{
	return -ENOSYS;
}

static inline int dt_read_u32(const struct device_node *node, const char *name, u32 *out)
{
	return -ENOSYS;
}

static inline int dt_read_u64_index(const struct device_node *node, const char *name, u64 *out, int index)
{
	return -ENOSYS;
}

static inline int dt_read_u64_array(const struct device_node *node, const char *name, u64 *out, size_t sz)
{
	return -ENOSYS;
}
static inline int dt_read_u64(const struct device_node *node, const char *name, u64 *out)
{
	return -ENOSYS;
}

static inline int dt_read_string(const struct device_node *node, const char *name, const char **out)
{
	return -ENOSYS;
}

static inline int dt_match_string(struct device_node *node, const char *name, const char *string)
{
	return -ENOSYS;
}

static inline int dt_count_strings(struct device_node *node, const char *name)
{
	return -ENOSYS;
}

static inline int dt_read_string_index(struct device_node *node, const char *name,
		int index, const char **out)
{
	return -ENOSYS;
}

static inline const u32 *dt_next_u32(struct property *pp, const u32 *cur, u32 *val)
{
	return NULL;
}

static inline const char *dt_next_string(struct property *pp, const char *cur)
{
	return NULL;
}

/**
 *增加/减少设备树节点引用值
 */
static inline struct device_node *dt_node_hold(struct device_node *node)
{
	return NULL;
}

static inline void dt_node_loosen(struct device_node *node)
{
	return;
}

static inline struct device_node *dt_node_add(struct device_node *parent, const char *name)
{
	return NULL;
}

static inline int dt_node_remove(struct device_node *node)
{
	return -ENOSYS;
}

static inline int dt_node_dup(struct device_node *parent, const char *name, struct device_node *src)
{
	return -ENOSYS;
}

static inline int dt_node_get_path(char *out, size_t out_len, const struct device_node *node)
{
	return -ENOSYS;
}

static inline struct device_node *dt_get_child_by_path(struct device_node *node, const char *path)
{
	return NULL;
}

static inline struct device_node *dt_find_node_by_path(const char *path)
{
	return NULL;
}

static inline const struct dt_device_id *dt_match_node(const struct dt_device_id *matches,
					 const struct device_node *node)
{
	return NULL;
}

static inline struct device_node *dt_find_matching_node(struct device_node *node,
					  const struct dt_device_id *matches)
{
	return NULL;
}

static inline void dt_iterate_matching_node(struct device_node *node,
			      const struct dt_device_id *matches,
			      node_found_cb found,
			      void *found_data)
{
	return;
}

static inline int is_device_compatible(const struct device_node *node, const char *compatible)
{
	return -ENOSYS;
}

static inline bool is_device_available(const struct device_node *node)
{
	return FALSE;
}

static inline bool is_device_big_endian(struct device_node *node)
{
	return FALSE;
}

#define for_each_child_of_node(child, node) \
	for (child = dt_get_next_child(node, NULL); \
	     child; \
	     child = dt_get_next_child(node, child))
static inline bool is_node_have_child(const struct device_node *node)
{
	return FALSE;
}

static inline struct device_node *dt_get_next_child(const struct device_node *node,
		struct device_node *cur)
{
	return NULL;
}

static inline struct device_node *dt_find_by_phandle(u32 phandle)
{
	return NULL;
}

static inline struct device_node *dt_parse_phandle(const struct device_node *node,
				     const char *phandle_name,
				     int index)
{
	return NULL;
}

static inline int dt_parse_phandle_with_args(const struct device_node *node,
			       const char *list_name,
			       const char *cells_name,
			       int index,
			       struct dt_phandle_args *out)
{
	return -ENOSYS;
}

static inline int dt_phandle_count_with_args(const struct device_node *node,
			       const char *list_name,
			       const char *cells_name)
{
	return -ENOSYS;
}

static inline int dt_get_clock_freq(struct device_node *node, u32 *clock_freq)
{
	return -ENOSYS;
}

/**
 * 获取设备的中断个数
 */
static inline u32 dt_irq_count(struct device_node *device)
{
	return -ENOSYS;
}

/**
 * 解析并映射中断
 * dev: 要被映射中断的设备树节点
 * index: 映射的中断index
 */
static inline unsigned int dt_recognize_irq(struct device_node *dev, int index)
{
	return -ENOSYS;
}

static inline phys_addr_t dt_get_addr(struct device_node *node, u64 *size, int index)
{
	return 0;
}

static inline void __iomem *dt_reg_map(struct device_node *node, int index)
{
	return NULL;
}

static inline int dt_reg_name_to_index(struct device_node *node, const char *regname)
{
	return -ENOSYS;
}

static inline void __iomem *dt_reg_map_byname(struct device_node *node, const char *regname)
{
	return NULL;
}

static inline void __iomem *dt_reg_request_and_map(struct device_node *node,
		int index, const char *name)
{
	return NULL;
}

static inline int dt_reg_unmap_and_free(struct device_node *node, void *va, int index)
{
	return -ENOSYS;
}

static inline int dt_reserved_memory_init(void)
{
	return -ENOSYS;
}

static inline u32 dt_nidtbl_count(void)
{
	return -ENOSYS;
}

static inline struct dt_nidtbl *dt_nidtbl_get(int index)
{
	return NULL;
}

static inline const struct dt_device_id *dt_nidtbl_create_matches(const char *subsys)
{
	return NULL;
}

static inline void dt_nidtbl_destroy_matches(const struct dt_device_id *matches)
{
	return;
}

static inline int dt_init(void)
{
	return -ENOSYS;
}

static inline const char *dt_node_full_name(const struct device_node *np)
{
	return "<no-node>";
}

static inline void *dt_get_match_data(const struct device *dev)
{
	return NULL;
}

#endif

#endif /* __DIM_SUM_DT_H */
